#include "Oled_i2c.h"
#include "font.h"
#include "stm32f0xx_i2c.h"
#include "stm32f0xx_gpio.h"
#include "stm32f0xx_rcc.h"
#include "GlobalState.h"

// 使用I2C1
#define OLED_I2C I2C1
#define OLED_I2C_CLK RCC_APB1Periph_I2C1
#define OLED_GPIO_CLK RCC_AHBPeriph_GPIOB

// 使用PB8和PB9作为I2C引脚
#define OLED_SCL_PIN GPIO_Pin_8
#define OLED_SDA_PIN GPIO_Pin_9
#define OLED_GPIO GPIOB

// OLED地址
#define OLED_ADDR 0x78

// I2C通信超时时间
#define I2C_TIMEOUT 10000

// 控制字节
#define OLED_CMD 0x00
#define OLED_DATA 0x40

// 初始化I2C
static void I2C_Configuration(void)
{
    GPIO_InitTypeDef GPIO_InitStructure;
    I2C_InitTypeDef I2C_InitStructure;

    // 复位I2C外设
    RCC_APB1PeriphResetCmd(OLED_I2C_CLK, ENABLE);
    for(volatile uint32_t i = 0; i < 100; i++); // 短暂延时
    RCC_APB1PeriphResetCmd(OLED_I2C_CLK, DISABLE);

    // 使能时钟
    RCC_APB1PeriphClockCmd(OLED_I2C_CLK, ENABLE);
    RCC_AHBPeriphClockCmd(OLED_GPIO_CLK, ENABLE);

    // 配置GPIO
    GPIO_InitStructure.GPIO_Pin = OLED_SCL_PIN | OLED_SDA_PIN;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_InitStructure.GPIO_OType = GPIO_OType_OD;
    GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;
    GPIO_Init(OLED_GPIO, &GPIO_InitStructure);

    // 配置引脚复用
    GPIO_PinAFConfig(OLED_GPIO, GPIO_PinSource8, GPIO_AF_1);
    GPIO_PinAFConfig(OLED_GPIO, GPIO_PinSource9, GPIO_AF_1);

    // 配置I2C
    I2C_InitStructure.I2C_Mode = I2C_Mode_I2C;
    I2C_InitStructure.I2C_AnalogFilter = I2C_AnalogFilter_Enable;
    I2C_InitStructure.I2C_DigitalFilter = 0x00;
    I2C_InitStructure.I2C_OwnAddress1 = 0x00;
    I2C_InitStructure.I2C_Ack = I2C_Ack_Enable;
    I2C_InitStructure.I2C_AcknowledgedAddress = I2C_AcknowledgedAddress_7bit;
    // 配置I2C时序参数 (100KHz)
    // PRESC = 0x0, SCLDEL = 0x3, SDADEL = 0x1, SCLH = 0x3, SCLL = 0x9
    I2C_InitStructure.I2C_Timing = 0x00310309;

    I2C_Init(OLED_I2C, &I2C_InitStructure);
    I2C_Cmd(OLED_I2C, ENABLE);
}

// 发送命令
void OLED_WriteCmd(uint8_t cmd)
{
    while (I2C_GetFlagStatus(OLED_I2C, I2C_FLAG_BUSY) == SET)
        ;

    I2C_TransferHandling(OLED_I2C, OLED_ADDR, 2, I2C_AutoEnd_Mode, I2C_Generate_Start_Write);

    while (I2C_GetFlagStatus(OLED_I2C, I2C_FLAG_TXIS) == RESET)
        ;
    I2C_SendData(OLED_I2C, OLED_CMD);

    while (I2C_GetFlagStatus(OLED_I2C, I2C_FLAG_TXIS) == RESET)
        ;
    I2C_SendData(OLED_I2C, cmd);

    while (I2C_GetFlagStatus(OLED_I2C, I2C_FLAG_STOPF) == RESET)
        ;
    I2C_ClearFlag(OLED_I2C, I2C_FLAG_STOPF);
}

// 发送数据
static void OLED_WriteData(uint8_t data)
{
    while (I2C_GetFlagStatus(OLED_I2C, I2C_FLAG_BUSY) == SET)
        ;

    I2C_TransferHandling(OLED_I2C, OLED_ADDR, 2, I2C_AutoEnd_Mode, I2C_Generate_Start_Write);

    while (I2C_GetFlagStatus(OLED_I2C, I2C_FLAG_TXIS) == RESET)
        ;
    I2C_SendData(OLED_I2C, OLED_DATA);

    while (I2C_GetFlagStatus(OLED_I2C, I2C_FLAG_TXIS) == RESET)
        ;
    I2C_SendData(OLED_I2C, data);

    while (I2C_GetFlagStatus(OLED_I2C, I2C_FLAG_STOPF) == RESET)
        ;
    I2C_ClearFlag(OLED_I2C, I2C_FLAG_STOPF);
}

// 初始化OLED
// 在屏幕指定位置画一条横线
void DrawHorizontalLine(void)
{
    // 先清除屏幕
    OLED_Clear();

    // 根据当前页面状态选择绘制位置
    uint8_t target_page;
    switch (globalStatus.currentPage)
    {
    case 0: // 上方
        target_page = 1;
        break;
    case 1: // 中间
        target_page = OLED_PAGES / 2;
        break;
    case 2: // 下方
        target_page = OLED_PAGES - 2;
        break;
    default:
        target_page = OLED_PAGES / 2;
        break;
    }

    // 设置页地址
    OLED_WriteCmd(0xB0 + target_page);
    OLED_WriteCmd(0x00); // 设置列地址低4位
    OLED_WriteCmd(0x10); // 设置列地址高4位

    // 在整行画线（128像素宽）
    for (uint8_t i = 0; i < OLED_WIDTH; i++)
    {
        OLED_WriteData(0xFF); // 在这一行的所有像素点都点亮
    }
}

void OLED_I2C_Init(void)
{
    I2C_Configuration();

    // OLED初始化序列
    OLED_WriteCmd(0xAE); // 关闭显示
    OLED_WriteCmd(0xD5); // 设置显示时钟分频比/振荡器频率
    OLED_WriteCmd(0x80);
    OLED_WriteCmd(0xA8); // 设置多路复用率
    OLED_WriteCmd(0x3F);
    OLED_WriteCmd(0xD3); // 设置显示偏移
    OLED_WriteCmd(0x00);
    OLED_WriteCmd(0x40); // 设置显示开始行
    OLED_WriteCmd(0x8D); // 充电泵设置
    OLED_WriteCmd(0x14);
    OLED_WriteCmd(0x20); // 设置内存地址模式
    OLED_WriteCmd(0x02); // 页地址模式
    OLED_WriteCmd(0xA1); // 段重定义，反向扫描（从右到左）
    OLED_WriteCmd(0xC8); // COM扫描方向，反向扫描（从下到上）
    OLED_WriteCmd(0xDA); // COM硬件配置
    OLED_WriteCmd(0x12);
    OLED_WriteCmd(0x81); // 对比度设置
    OLED_WriteCmd(0x8F); // 降低对比度
    OLED_WriteCmd(0xD9); // 预充电周期
    OLED_WriteCmd(0xF1);
    OLED_WriteCmd(0xDB); // VCOMH电压
    OLED_WriteCmd(0x30);
    OLED_WriteCmd(0xA4); // 全局显示开启
    OLED_WriteCmd(0xA6); // 正常显示（非反显）
    OLED_WriteCmd(0xAF); // 开启显示

    OLED_Clear(); // 清屏
}

// 清屏
void OLED_Clear(void)
{
    for (uint8_t i = 0; i < OLED_PAGES; i++)
    {
        OLED_WriteCmd(0xB0 + i); // 设置页地址
        OLED_WriteCmd(0x00);     // 设置列地址低4位
        OLED_WriteCmd(0x10);     // 设置列地址高4位

        for (uint8_t j = 0; j < OLED_WIDTH; j++)
        {
            OLED_WriteData(0x00); // 修改为0x00使所有像素点熄灭
        }
    }
}

// 设置显示位置
void OLED_SetPosition(uint8_t x, uint8_t y)
{
    OLED_WriteCmd(0xB0 + y);
    OLED_WriteCmd(((x & 0xF0) >> 4) | 0x10);
    OLED_WriteCmd(x & 0x0F);
}

// 显示单个字符
void OLED_ShowChar(uint8_t x, uint8_t y, uint8_t index)
{
    // 确保y不会超出屏幕范围
    if (y + 2 > OLED_PAGES)
    {
        y = OLED_PAGES - 2;
    }

    // 显示8x16字符的两个页面
    for (uint8_t page = 0; page < 2; page++)
    {
        OLED_SetPosition(x, y + page);
        for (uint8_t col = 0; col < 8; col++)
        {
            OLED_WriteData(ASCII_8x16[index * 16 + page * 8 + col]);
        }
    }
}

// 在屏幕中间显示LOADING
void OLED_DisplayLoading(void)
{
    // 先清除屏幕
    OLED_Clear();

    // 计算起始位置，使LOADING居中显示
    uint8_t start_x = (OLED_WIDTH - (8 * 7)) / 2; // 水平居中，7个字母
    uint8_t start_y = (OLED_PAGES - 2) / 2;       // 垂直居中，每个字符占2页

    // 显示LOADING
    OLED_ShowChar(start_x, start_y, CHAR_L);
    OLED_ShowChar(start_x + 8, start_y, CHAR_O);
    OLED_ShowChar(start_x + 16, start_y, CHAR_A);
    OLED_ShowChar(start_x + 24, start_y, CHAR_D);
    OLED_ShowChar(start_x + 32, start_y, CHAR_I);
    OLED_ShowChar(start_x + 40, start_y, CHAR_N);
    OLED_ShowChar(start_x + 48, start_y, CHAR_G);
}